#pragma once
#include "../mqcommon/helper.hpp"
#include "../mqcommon/logger.hpp"
#include "../mqcommon/msg.pb.h"
#include <unordered_map>
#include <mutex>
#include <google/protobuf/map.h>

struct MsgQueue
{
    using Ptr = std::shared_ptr<MsgQueue>;
    std::string name;
    bool durable;
    bool exclusive;
    bool autoDelete;
    google::protobuf::Map<std::string, std::string> args;

    MsgQueue(const std::string& msgQueueName
            ,bool msgQueuedurable
            ,bool msgQueueexclusive
            ,bool msgQueueautoDelete
            ,const google::protobuf::Map<std::string, std::string>& msgQueueargs)
        :name(msgQueueName), durable(msgQueuedurable), exclusive(msgQueueexclusive), autoDelete(msgQueueautoDelete), args(msgQueueargs)
    {}
    MsgQueue() {}
    ~MsgQueue() {}
    
    std::string serializeArgs()    //序列化args存储到sqlite里：格式key=value;
    {
        std::string str;
        for(auto& arg : args)
            str += arg.first + "=" + arg.second + ";";
        return str;
    }

    void deSerializeArgs(const std::string& str)  //反序列化args
    {
        std::vector<std::string> rows;
        SplitHelper::split(str, ";", rows);
        for(auto& row : rows)
        {
            int pos = row.find("=");
            args.insert({row.substr(0, pos), row.substr(pos + 1)});
        }
    }
};

class MsgQueueMapper
{
public:
    MsgQueueMapper(const std::string& dbfile)
        :_helper(dbfile)
    {
        std::string parentDirectory = FileHelper::getParentDirectory(dbfile);
        FileHelper::createDirectory(parentDirectory);
        _helper.open();
        createTable();
    }
    ~MsgQueueMapper() {}
    void createTable()
    {
        std::string createTableSql = "create table if not exists msgqueue_table(name varchar(32) primary key, durable int, exclusive int, auto_delete int, args varchar(64));";
        assert(_helper.exec(createTableSql));        //创表失败，直接终止
    }
    void removeTable()
    {
        std::string removeTableSql = "drop table if exists msgqueue_table;";
        assert(_helper.exec(removeTableSql));  
    }
    bool insert(MsgQueue::Ptr ptr)
    {
        char insertSql[256] = {0};
        sprintf(insertSql, "insert into msgqueue_table values('%s', %d, %d, %d, '%s');"
            , ptr->name.c_str()
            ,ptr->durable
            ,ptr->exclusive
            ,ptr->autoDelete
            ,ptr->serializeArgs().c_str());
        return _helper.exec(insertSql);

    }
    bool remove(const std::string& name)
    {
        char removeSql[256] = {0};
        sprintf(removeSql, "delete from msgqueue_table where name='%s';", name.c_str());
        return _helper.exec(removeSql);
    }
    std::unordered_map<std::string, MsgQueue::Ptr> recovery()
    {
        std::unordered_map<std::string, MsgQueue::Ptr> result;
        std::string selectSql = "select * from msgqueue_table;";
        _helper.exec(selectSql, msgQueueCallback, &result);
        return result;
    }
private:
    static int msgQueueCallback(void* args, int colNum, char** colValues, char** colName)
    {
        std::unordered_map<std::string, MsgQueue::Ptr>* pResult = static_cast<std::unordered_map<std::string, MsgQueue::Ptr>*>(args);
        MsgQueue::Ptr pMsgQueue = std::make_shared<MsgQueue>();
        pMsgQueue->name = colValues[0];
        pMsgQueue->durable = std::stoi(colValues[1]);
        pMsgQueue->exclusive = std::stoi(colValues[2]);
        pMsgQueue->autoDelete = std::stoi(colValues[3]);
        if(colValues[4]) pMsgQueue->deSerializeArgs(colValues[4]);
        pResult->insert({pMsgQueue->name, pMsgQueue});          //忘记插入的导致没有恢复成功
        return 0;
    }
private:
    SqliteHelper _helper;
};

class MsgQueueManager
{
public:
    using Ptr = std::shared_ptr<MsgQueueManager>;
    MsgQueueManager(const std::string& msgQueueName)
        :_mapper(msgQueueName)
    {
        _msgqueues = _mapper.recovery();
    }
    //增加队列
    void declareMsgQueue(const std::string& msgQueueName
            ,bool msgQueuedurable
            ,bool msgQueueexclusive
            ,bool msgQueueautoDelete
            ,const google::protobuf::Map<std::string, std::string>& msgQueueargs)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        auto it = _msgqueues.find(msgQueueName);
        if(it != _msgqueues.end()) return ;
        MsgQueue::Ptr pMsgQueue = std::make_shared<MsgQueue>(msgQueueName, msgQueuedurable, msgQueueexclusive, msgQueueautoDelete, msgQueueargs);
        if(msgQueuedurable)
            _mapper.insert(pMsgQueue);
        _msgqueues.insert({msgQueueName, pMsgQueue});
    }
    //删除指定队列
    void deleteMsgQueue(const std::string& msgQueueName)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        auto it = _msgqueues.find(msgQueueName);
        if(it == _msgqueues.end()) return;
        // if(it->second->durable == false)     //修改下，这里并不需要，持久化是备份有效数据，删除了就是无效数据，备份的也要删掉
        _mapper.remove(msgQueueName);
        _msgqueues.erase(msgQueueName);
    }
    //获取指定队列
    MsgQueue::Ptr selectMsgQueue(const std::string& msgQueueName)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        auto it = _msgqueues.find(msgQueueName);
        if(it == _msgqueues.end()) return MsgQueue::Ptr();
        return it->second;
    }
    std::unordered_map<std::string, MsgQueue::Ptr> getAllMsgQueue()
    {
        std::unique_lock<std::mutex> lock(_mutex);
        return _msgqueues;
    }
    bool exists(const std::string& msgQueueName)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        auto it = _msgqueues.find(msgQueueName);
        if(it == _msgqueues.end()) return false;
        else return true;
    }
    //清理资源
    void clear()
    {
        std::unique_lock<std::mutex> lock(_mutex);
        for(auto& msgQueue : _msgqueues)
            // if(msgQueue.second->durable == false)
                _mapper.remove(msgQueue.second->name);      //同样的道理
        _msgqueues.clear();
    }
    size_t size()
    {
        return _msgqueues.size();
    }
private:
    std::mutex _mutex;
    MsgQueueMapper _mapper;
    std::unordered_map<std::string, MsgQueue::Ptr> _msgqueues;
};